package com.expert.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.expert.Mapper.MenuMapper;
import com.expert.Mapper.RoleMapper;
import com.expert.Mapper.UserMapper;
import com.expert.constant.MessageConstant;
import com.expert.constant.RedisKeyConstant;
import com.expert.context.BaseContext;
import com.expert.dto.EditRoleDTO;
import com.expert.dto.UpdateRoleMenuDTO;
import com.expert.exception.AddException;
import com.expert.exception.DataQueryException;
import com.expert.exception.DeleteException;
import com.expert.exception.UpdateException;
import com.expert.pojo.Menu;
import com.expert.pojo.Role;
import com.expert.pojo.RoleMenu;
import com.expert.pojo.User;
import com.expert.service.RoleMenuService;
import com.expert.service.RoleService;
import com.expert.service.UserService;
import com.expert.vo.AssignMenuVo;
import com.expert.vo.MenuVo;
import com.expert.vo.RoleVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @ClassName: MenuSericeImpl
 * @Author: cxs
 * @Date: 2024/01/24 13:48
 * @Description:
 **/

@Service
@Slf4j
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Autowired
    MenuMapper menuMapper;
    @Autowired
    UserMapper userMapper;

    @Autowired
    RoleMenuService roleMenuService;
    @Autowired
    RedisTemplate<String, List<MenuVo>> redisTemplate;
    /**
     * 获取role的列表
     *
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public List<Role> getRoleList() {
        List<Role> roleList = this.list();
        return roleList.stream().peek(role -> {
            Role.builder().id(role.getId()).roleName(role.getRoleName()).build();
        }).toList();
    }

    /**
     * 分页查询角色
     *
     * @param page     当前页
     * @param pageSize 每页个数
     * @param roleName 角色名
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public Page<RoleVo> getRolePage(int page, int pageSize, String roleName, String roleCode) {
        Page<Role> rolePage = new Page<>(page, pageSize);
        page(rolePage, new LambdaQueryWrapper<Role>()
                .like(StringUtils.isNotEmpty(roleName), Role::getRoleName, roleName)
                .like(StringUtils.isNotEmpty(roleCode), Role::getRoleCode, roleCode)
                .orderByAsc(Role::getUpdateTime));
        Page<RoleVo> roleVoPage = new Page<>(page, pageSize);
        //复制新的rolePage
        BeanUtils.copyProperties(rolePage, roleVoPage);
        //处理新数据
        List<RoleVo> collect = rolePage.getRecords().stream().map(item -> {
            RoleVo roleVo = new RoleVo();
            BeanUtils.copyProperties(item, roleVo);
            //获取菜单信息
            List<RoleMenu> roleMenus = this.roleMenuService.lambdaQuery().eq(RoleMenu::getRoleId, item.getId()).list();
            List<Long> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
            //遍历menuIds查询菜单名，并拼接字符串
            List<Menu> menus=new ArrayList<>();
            if (menuIds.size()>0) {
                 menus = menuMapper.selectBatchIds(menuIds);
            }
            StringBuilder stringBuilder = new StringBuilder();
            menus.forEach(menu -> {
                stringBuilder.append(menu.getTitle()).append(",");
            });
            String menuString ="";
            if(stringBuilder.length()>0) {
                menuString=stringBuilder.substring(0, stringBuilder.length() - 1);
            }
            roleVo.setMenuString(menuString);
            User user = userMapper.selectById(item.getCreateUser());
            if (user != null) {
                roleVo.setCreateUserName(user.getName());
            }
            return roleVo;
        }).toList();
        roleVoPage.setRecords(collect);
        return roleVoPage;
    }

    /**
     * 删除角色信息
     *
     * @param ids 待删除角色id
     */
    @Override
    @Transactional
    public void deleteRoles(ArrayList<Long> ids) {
        //首先判断id是否存在默认的三个角色,或者是否存在用户拥有此角色权限
        ArrayList<Long> defaultIds = new ArrayList<>();
        Collections.addAll(defaultIds, 1L, 2L, 3L);
        defaultIds.forEach(d -> {
            if (ids.contains(d)) {
                throw new DeleteException(MessageConstant.ROLE_DELETE_FAIL_DEFAULT_IDS);
            }
        });
        ids.forEach(id->{
            //判断是否有用户存在此权限
            List<User> users = this.userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getRole, id));
            if (users != null && users.size() > 0) {
                //TODO 将字符串封装成常量
                throw new DeleteException("存在用户拥有此角色，删除失败！");
            }
        });


        //删除内容
        this.removeBatchByIds(ids);
        //删除角色菜单
        ids.forEach(id->{
            this.roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId,id));
        });
    }

    /**
     * 检查新增角色信息是否重复
     *
     * @param roleCode 新增角色代号
     */
    @Override
    public void checkRoleRepeat(String roleCode) {
        List<Role> list = this.lambdaQuery().eq(Role::getRoleCode, roleCode).list();
        System.out.println(list);
        if (list.size() > 0) {
            throw new AddException(MessageConstant.ROLE_ADD_FAIL_REPEAT);
        }
    }

    /**
     * 检查新增角色名字是否重复
     *
     * @param roleName
     * @return
     */
    @Override
    public boolean checkRoleNameRepeat(String roleName) {
        List<Role> list = this.lambdaQuery().eq(Role::getRoleName, roleName).list();
        return list.size() > 0;
    }

    /**
     * 添加新角色
     *
     * @param role 待添加角色
     */
    @Override
    public void addRole(Role role) {
        //首先判断前端传递的内容是否为空以及roleCode是否存在
        if ((role.getRoleName() == null || "".equals(role.getRoleName())) || (role.getRoleCode() == null || "".equals(role.getRoleCode())) || role.getRoleLevel() == null) {
            throw new AddException(MessageConstant.ROLE_ADD_FAIL_EMPTY);
        }
        //校验是否重复
        this.checkRoleRepeat(role.getRoleCode());
        //设置剩余内容
        role.setCreateTime(LocalDateTime.now());
        role.setUpdateTime(LocalDateTime.now());
        role.setUpdateUser(BaseContext.getCurrentId());
        role.setCreateUser(BaseContext.getCurrentId());
        this.save(role);
        RoleMenu roleMenu=new RoleMenu();
        roleMenu.setMenuId(0L);
        roleMenu.setRoleId(role.getId());
        roleMenu.setCreateUser(BaseContext.getCurrentId());
        roleMenu.setCreateTime(LocalDateTime.now());
        roleMenu.setUpdateUser(BaseContext.getCurrentId());
        roleMenu.setUpdateTime(LocalDateTime.now());
        this.roleMenuService.save(roleMenu);
    }

    /**
     * 根据id查询角色信息
     *
     * @param id
     * @return
     */
    @Override
    public Role getRoleById(Long id) {
        Role one = this.lambdaQuery().eq(Role::getId, id).one();
        if (one == null) {
            throw new DataQueryException(MessageConstant.ROLE_QUERY_BY_ID_FAIL);
        }
        return one;
    }

    /**
     * 修改用户信息
     *
     * @param editRoleDTO
     */
    @Override
    @Transactional
    public void updateRole(EditRoleDTO editRoleDTO) {
        //首先判断内容合理性
        if (editRoleDTO.getRoleName() == null || editRoleDTO.getRoleLevel() == null || editRoleDTO.getRoleCode() == null || editRoleDTO.getId() == null) {
            throw new UpdateException(MessageConstant.ROLE_UPDATE_FAIL);
        }
        Long roleDTOId = editRoleDTO.getId();
        ArrayList<Long> defaultId = new ArrayList<>();
        Collections.addAll(defaultId, 1L, 2L, 3L);
        if (defaultId.contains(roleDTOId)) {
            throw new UpdateException(MessageConstant.ROLE_DELETE_UPDATE_DEFAULT_IDS);
        }

        Role role = new Role();
        BeanUtils.copyProperties(editRoleDTO, role);
        //校验是否存在相同的roleCode
        Role one = this.lambdaQuery().eq(Role::getRoleCode, role.getRoleCode()).ne(Role::getId, role.getId()).one();
        if (one != null) {
            throw new UpdateException(MessageConstant.ROLE_UPDATE_REPEAT);
        }
        role.setUpdateTime(LocalDateTime.now());
        role.setUpdateUser(BaseContext.getCurrentId());
        this.updateById(role);
    }

    /**
     * 获取菜单信息
     *
     * @return
     */
    @Override
    public List<AssignMenuVo> getAssignMenu()  {
        //首先获取所有的菜单
        List<Menu> menus = this.menuMapper.selectList(null);
        List<AssignMenuVo> assignMenuVoList = new ArrayList<>();
        menus.forEach(item -> {
            AssignMenuVo assignMenuVo = new AssignMenuVo();
            BeanUtils.copyProperties(item, assignMenuVo);
            assignMenuVoList.add(assignMenuVo);
        });
        //构建树形结构
        List<AssignMenuVo> assignMenuTree = new ArrayList<>();
        if (assignMenuVoList.size() > 0) {
            assignMenuTree = buildDeptTreeByStream(assignMenuVoList);
        }
        return assignMenuTree;
    }

    /**
     * 获取用户默认菜单列表
     *
     * @param id
     * @return
     */
    @Override
    public List<Long> getRoleDefaultIds(Long id) {
        Role role = this.lambdaQuery().eq(Role::getId, id).one();
        if (role == null) {
            throw new DataQueryException("角色不存在！");
        }
        List<RoleMenu> roleMenus = this.roleMenuService.lambdaQuery().eq(RoleMenu::getRoleId,id).list();
        List<Long> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).toList();
        ArrayList<Long> ids = new ArrayList<>();
        if (menuIds.size() > 0) {
            List<Menu> menus = this.menuMapper.selectBatchIds(menuIds);
            List<AssignMenuVo> newList = menus.stream().map(item -> {
                AssignMenuVo assignMenuVo = new AssignMenuVo();
                BeanUtils.copyProperties(item, assignMenuVo);
                return assignMenuVo;
            }).toList();
            //构建树形结构
            List<AssignMenuVo> menuTree = new ArrayList<>();
            if (newList.size() > 0) {
                menuTree = buildDeptTreeByStream(newList);
            }
            //查找存在子树的
            menuTree.forEach(menuId -> {
                if (menuId.getChildrenItem() == null) {
                    ids.add(menuId.getId());
                } else {
                    menuId.getChildrenItem().forEach(child -> {
                        ids.add(child.getId());
                    });
                }
            });
        }
        return ids;
    }


    /**
     * 修改角色菜单
     *
     * @param menuDTO
     */
    @Override
    @Transactional
    public void updateRoleMenu(UpdateRoleMenuDTO menuDTO) {
        List<Long> ids = menuDTO.getIds();
        this.roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId,menuDTO.getId()));
        if (ids.size() == 0) {
            RoleMenu roleMenu1=new RoleMenu();
            roleMenu1.setMenuId(0L);
            roleMenu1.setRoleId(menuDTO.getId());
            roleMenu1.setCreateUser(BaseContext.getCurrentId());
            roleMenu1.setCreateTime(LocalDateTime.now());
            roleMenu1.setUpdateUser(BaseContext.getCurrentId());
            roleMenu1.setUpdateTime(LocalDateTime.now());
            this.roleMenuService.save(roleMenu1);
        } else {
            ids.forEach(id -> {
                RoleMenu roleMenu=new RoleMenu();
                roleMenu.setMenuId(id);
                roleMenu.setRoleId(menuDTO.getId());
                roleMenu.setCreateUser(BaseContext.getCurrentId());
                roleMenu.setCreateTime(LocalDateTime.now());
                roleMenu.setUpdateUser(BaseContext.getCurrentId());
                roleMenu.setUpdateTime(LocalDateTime.now());
                this.roleMenuService.save(roleMenu);
            });
            //删除缓存的菜单信息

            redisTemplate.delete(RedisKeyConstant.SYSTEM_MENU_CACHE+menuDTO.getId());
        }
    }

    private List<AssignMenuVo> buildDeptTreeByStream(List<AssignMenuVo> trees) {
        //获取parentId = 0的根节点
        List<AssignMenuVo> list = trees.stream().filter(item -> item.getPid() == 0L).collect(Collectors.toList());
        //根据parentId进行分组
        Map<Long, List<AssignMenuVo>> map = trees.stream().collect(Collectors.groupingBy(AssignMenuVo::getPid));
        recursionFnTree(list, map);
        return list;
    }

    /**
     * 递归遍历节点
     *
     * @param list
     * @param map
     */
    private void recursionFnTree(List<AssignMenuVo> list, Map<Long, List<AssignMenuVo>> map) {
        for (AssignMenuVo treeSelect : list) {
            List<AssignMenuVo> childList = map.get(treeSelect.getId());
            treeSelect.setChildrenItem(childList);
            if (null != childList && 0 < childList.size()) {
                recursionFnTree(childList, map);
            }
        }
    }
}
